from django.db.models import F
from django.utils.timezone import get_default_timezone_name

from mongolog.models import ShareLog, CASLog
from rest_framework import serializers
from zmad.models import ZTPUser, ZTPGroup
from .models import UserDemand, DailySummary, Device


class UserSerializer(serializers.ModelSerializer):
    status = serializers.SerializerMethodField()
    group_name = serializers.SerializerMethodField()

    def get_status(self, instance):
        if instance.blocked:
            return 'blocked'
        if instance.enabled:
            return 'enabled'
        return 'disabled'

    def get_group_name(self, instance):
        return instance.belong_to.name

    class Meta:
        model = ZTPUser
        fields = ('id', 'username', 'phone', 'employee_id', 'name', 'email', 'status', 'belong_to', 'group_name')


class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = ZTPGroup
        fields = ('id', 'name', 'parent')


class UserWithGroupSerializer(UserSerializer):
    belong_to = GroupSerializer()

    class Meta:
        model = ZTPUser
        fields = ('id', 'username', 'phone', 'employee_id', 'name', 'email', 'status', 'belong_to')


class UserDemandSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDemand
        fields = ('demand',)


class UserDetailSerializer(UserWithGroupSerializer):
    demands = serializers.SerializerMethodField()

    def get_demands(self, instance):
        return list(set(ud.demand for ud in instance.nonnull_demands))

    class Meta:
        model = ZTPUser
        fields = ('id', 'username', 'phone', 'employee_id', 'name', 'last_ip',
                  'email', 'status', 'belong_to', 'demands', "safety_score")


class UserDeviceSerializer(UserWithGroupSerializer):
    strategy = serializers.SerializerMethodField()

    class Meta:
        model = Device
        fields = ('id', 'device_type', 'device_type_str', 'device_uuid', 'model', 'os_version', 'strategy', 'risk_list')



class DailySummarySerializer(serializers.ModelSerializer):
    class Meta:
        model = DailySummary
        exclude = ('id',)


def relationship_serializer(**filters):
    aggregation = [{
        '$group': {
            '_id': {
                'from': '$username',
                'to': '$send_to'
            },
            'count': {'$sum': 1}
        }
    }]
    if filters:
        match = {}
        username = filters.pop('username', None)
        if username:
            match.update({'$or': [
                {'username': username},
                {'send_to': username},
            ]})
        match.update(filters)
        aggregation.insert(0, {'$match': match})

    queryset1 = ShareLog.objects.mongo_aggregate(aggregation)
    queryset2 = ZTPUser.objects.annotate(group=F('belong_to')).values('username', 'name', 'group')
    user_mapping = {user.pop('username'): user for user in queryset2}
    nodes = set()
    links = []
    for agg in queryset1:
        source = agg['_id']['from']
        target = agg['_id']['to']
        # 有一部分脏数据，需要过滤掉
        if source in user_mapping and target in user_mapping:
            nodes.add(source)
            nodes.add(target)
            links.append({'source': source, 'target': target, 'weight': agg['count']})
    nodes = [{'id': x, **user_mapping[x]} for x in nodes]
    return {'nodes': nodes, 'links': links}


def app_visit_serializer(username=None, auth_code=None, resource=None, platform=None):
    aggregation = [
        {'$match': {
            'resource': {'$exists': True},  # 这里需要过滤
            'platform': {'$exists': True},
        }},
        {
            '$group': {
                '_id': '$username',
                'apps': {'$addToSet': '$resource'},
                'visit_count': {'$sum': 1},
                'regions': {'$addToSet': '$ip_location.region_name'}
            }
        },
        {
            '$project': {
                'app_count': {'$size': '$apps'},
                'visit_count': 1,
                "regions": "$regions"
            }
        }
    ]
    if isinstance(username, (list, tuple)):
        aggregation.insert(0, {'$match': {'username': {'$in': username}}})
    elif isinstance(username, str):
        aggregation.insert(0, {'$match': {'username': username}})
    if auth_code:
        aggregation.insert(0, {'$match': {'auth_code': auth_code}})
    if platform:
        aggregation[0]['$match']['platform'] = platform
    if resource:
        aggregation[0]['$match']['resource'] = resource
    queryset = CASLog.objects.mongo_aggregate(aggregation)

    data = list()
    for agg in queryset:
        if "局域网" in agg["regions"]:
            agg["regions"].remove("局域网")
        temp_dict = {
            'username': agg['_id'],
            'app_count': agg['app_count'],
            'visit_count': agg['visit_count'],
            "regions": agg["regions"]
        }
        data.append(temp_dict)

    if isinstance(username, str):
        try:
            return data[0]
        except IndexError:
            return {'username': username, 'app_count': 0, 'visit_count': 0}
    return data


def device_geotrack_serializer(show_devices=True, **filters):
    aggregation = [
        {
            '$match': {
                'ip_location.city_name': {
                    '$exists': True,
                    '$ne': ''
                },
                **filters
            }
        },
        {
            '$group': {
                '_id': '$ip_location.city_name',
                'latitude': {'$first': '$ip_location.latitude'},
                'longitude': {'$first': '$ip_location.longitude'},
                'count': {'$sum': 1},
                'last_visit': {'$max': '$log_time'}
            }
        },
        {
            '$project': {
                '_id': 0,
                'city': {
                    'name': '$_id',
                    'latitude': '$latitude',
                    'longitude': '$longitude',
                },
                'count': 1,
                'last_visit': {
                    '$dateToString': {
                        'date': '$last_visit',
                        'format': '%Y-%m-%d %H:%M:%S',
                        'timezone': get_default_timezone_name()
                    }
                }
            }
        }
    ]
    if show_devices:
        aggregation[1]['$group']['device'] = {'$addToSet': '$device_fingerprint.device_model'}
        aggregation[2]['$project']['device'] = 1

    queryset = CASLog.objects.mongo_aggregate(aggregation)
    return list(queryset)
